package bibp2pdesk;

import XMLCatalog.CatalogClass;
import XMLCatalog.FileClass;
import XMLCatalog.ObjectFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Catalog {

    private static final String CATALOG_PATH = "/tmp/catalog.xml";
    private boolean isCatalog;
    private ObjectFactory factory;
    private CatalogClass catalog;
    private CatalogServer server;
    private String ip;

    public Catalog(boolean isCatalog, String ip) {

        this.isCatalog = isCatalog;
        factory = new ObjectFactory();

        this.ip = ip;

        if (isCatalog == true) {

            server = new CatalogServer(ip);
            server.start();

        }

    }

    public FileClass createFile() {

        FileClass file = factory.createFileClass();
        return file;

    }

    public List<FileClass> searchFile(FileClass model) throws Exception {

        try {
            
            CatalogClient client = new CatalogClient(this.ip);
            byte data[] = marshalFile(model);
            client.sendData(2, data);

            int type = client.recvType();
            data = client.recvData();

            if (type == 4)
                return unmarshalCatalog(data).getFile();

        } catch (Exception ex) {
            Logger.getLogger(Catalog.class.getName()).log(Level.SEVERE, null, ex);
        }

        throw new Exception("Entrada não encontrada");

    }

    public boolean insertFile(FileClass file) throws Exception {

        try {

            CatalogClient client = new CatalogClient(this.ip);
            byte data[] = marshalFile(file);
            client.sendData(1, data);

            int type = client.recvType();
            data = client.recvData();

            if (type == 4)
                return true;

            

        } catch (Exception ex) {
            Logger.getLogger(Catalog.class.getName()).log(Level.SEVERE, null, ex);
        }

        throw new Exception("Erro ao inserir no catalogo");
    }

    public void saveFile(FileClass file, String path) {

        try {

            byte[] data;
            data = marshalFile(file);
            FileOutputStream out = new FileOutputStream(path);
            out.write(data);

        } catch (IOException ex) {

            System.err.println("Erro ao salvar o arquivo " + path);

        }
    }

    @SuppressWarnings("unchecked")
    public FileClass loadFile(String path) {

        try {

            FileInputStream in = new FileInputStream(path);

            byte[] data = new byte[in.available()];
            in.read(data);

            return unmarshalFile(data);

        } catch (IOException ex) {

            System.err.println("Arquivo " + path + " não encontrado");

        }

        return null;

    }

    public byte[] marshalCatalog(CatalogClass catalog) {

        try {

            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            JAXBElement<CatalogClass> cc = factory.createCatalog(catalog);
            Marshaller m = jc.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));

            StringWriter sw = new StringWriter();
            m.marshal(cc, sw);
            return sw.toString().getBytes();

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
            System.err.println("Erro no formato do catalogo XML.");

        }

        return null;

    }

    public CatalogClass unmarshalCatalog(byte[] data) {

        CatalogClass catalog = factory.createCatalogClass();

        try {

            ByteArrayInputStream in = new ByteArrayInputStream(data);
            if (in == null) {
                return null;
            }
            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            Unmarshaller u = jc.createUnmarshaller();
            JAXBElement<CatalogClass> cc;
            cc = (JAXBElement<CatalogClass>) u.unmarshal(in);
            catalog = (CatalogClass) cc.getValue();

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
//			e.printStackTrace();
            System.err.println("Formato do catalogo XML inválido");

        }

        return catalog;

    }

    public byte[] marshalFile(FileClass file) {

        try {

            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            JAXBElement<FileClass> fc = factory.createFile(file);
            Marshaller m = jc.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));

//	     		m.marshal( fc, new FileOutputStream(path) );
            StringWriter sw = new StringWriter();
            m.marshal(fc, sw);

            return sw.toString().getBytes();

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
            e.printStackTrace();

        }

        return null;

    }

    @SuppressWarnings("unchecked")
    public FileClass unmarshalFile(byte[] data) {

        try {

            ByteArrayInputStream in = new ByteArrayInputStream(data);
            if (in == null) {
                return null;
            }
            JAXBContext jc = JAXBContext.newInstance("XMLCatalog");
            Unmarshaller u = jc.createUnmarshaller();
            JAXBElement<FileClass> fc = (JAXBElement<FileClass>) u.unmarshal(in);
            FileClass file = (FileClass) fc.getValue();
            return file;

        } catch (JAXBException e) {

            // TODO Auto-generated catch block
//			e.printStackTrace();
            System.err.println("Formato do arquivo XML inválido");

        }

        return null;

    }
}
